using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using NUnit.Framework;
using PropertyExpression.Common;

namespace PropertyExpression.ControllableQuery.Test
{
    [TestFixture]
    public partial class DemoTest
    {
        [Test]
        public void Test01()
        {
            //TODO: fix this
//            foreach (var record in MaterializeReader(
//                _ =>
//                    {
//                        var q = new Q(
//                            @"SELECT
//    ModelPublication.PublicationId,
//    ModelPublication.ModelCode,
//    ModelPublication.ModelSequence
//FROM
//    ModelPublication
//WHERE
//    1 = 1");
//                        if (_.ModelCode.HasValue) q._(@"
//    AND ModelPublication.ModelCode = ")._(_.ModelCode.Value);
//                        if (_.ModelSequence.HasValue) q._(@"
//    AND ModelPublication.ModelSequence = ")._(_.ModelSequence.Value);
//                        return q.ToString().Query(new
//                            {
//                                PublicationId = default(Guid),
//                                ModelCode = default(NVarChar<L4000>),
//                                ModelSequence = default(NVarChar<L4000>)
//                            });
//                    },
//                context => new
//                    {
//                        ModelCode = "ModelCode1".ToOptionIfNullOrEmpty().Select(_ => context.Param(_)),
//                        ModelSequence = "ModelSequence1".ToOptionIfNullOrEmpty().Select(_ => context.Param(_))
//                    }))
//            {
//                Console.WriteLine(
//                    "PublicationId = '{0}', ModelCode = '{1}', ModelSequence = '{2}'",
//                    record.PublicationId,
//                    record.ModelCode,
//                    record.ModelSequence);
//            }
        }

        public IEnumerable<TResult> MaterializeReader<T, TResult>(
            Func<T, IQuery<TResult>> func, Func<SqlCommand, T> arg)
        {
            return MainTest.ExecuteReader(context => func(arg(context))).Select(reader => reader.Materialize());
        }

        [Test]
        public void Test1()
        {
            //TODO: this this
            //foreach (var modelPublicationInfo in MainTest.ExecuteReader(
            //    context => GetModelPublications1(
            //        context.Param("ModelCode1"),
            //        context.Param("ModelSequence1")))
            //    .Select(reader => reader.Materialize()))
            //{
            //    Console.WriteLine(
            //        "PublicationId = '{0}', ModelCode = '{1}', ModelSequence = '{2}'",
            //        modelPublicationInfo.PublicationId,
            //        modelPublicationInfo.ModelCode,
            //        modelPublicationInfo.ModelSequence
            //        );
            //}
        }

        private static IQuery<IModelPublicationInfo1> GetModelPublications1(IParam<string> modelCode, IParam<string> modelSequence)
        {
            return new Q(@"SELECT
    ModelPublication.PublicationId,
    ModelPublication.ModelCode,
    ModelPublication.ModelSequence
FROM
    ModelPublication
WHERE
    ModelPublication.ModelCode = ")._(modelCode)._(@"
    AND ModelPublication.ModelSequence = ")._(modelSequence).Query<IModelPublicationInfo1>();
        }

        [Test]
        public void Test2()
        {
            foreach (var reader in MainTest.ExecuteReader(
                context => GetModelPublications2(
                    context.Param("ModelCode1"),
                    context.Param("ModelSequence1"))))
            {
                Console.WriteLine(
                    "PublicationId = '{0}', ModelCode = '{1}', ModelSequence = '{2}'",
                    reader.Item1(),
                    reader.Item2(),
                    reader.Item3()
                    );
            }
        }

        private static IQuery<Tuple<Guid, NVarChar<L4000>, NVarChar<L4000>>> GetModelPublications2(IParam<string> modelCode, IParam<string> modelSequence)
        {
            return new Q(@"SELECT
    ModelPublication.PublicationId AS Item1,
    ModelPublication.ModelCode AS Item2,
    ModelPublication.ModelSequence AS Item3
FROM
    ModelPublication
WHERE
    ModelPublication.ModelCode = ")._(modelCode)._(@"
    AND ModelPublication.ModelSequence = ")._(modelSequence).Query<Tuple<Guid, NVarChar<L4000>, NVarChar<L4000>>>();
        }

        [Test]
        public void Test3()
        {
            foreach (var modelPublicationInfo in MainTest.ExecuteReader(
                context => GetModelPublications3(
                    context.Param("ModelCode1"),
                    context.Param("ModelSequence1")))
                .Select(reader => new ModelPublicationInfo3(
                                      reader.PublicationId(),
                                      reader.ModelCode(),
                                      reader.ModelSequence())))
            {
                Console.WriteLine(
                    "PublicationId = '{0}', ModelCode = '{1}', ModelSequence = '{2}'",
                    modelPublicationInfo.PublicationId,
                    modelPublicationInfo.ModelCode,
                    modelPublicationInfo.ModelSequence
                    );
            }
        }

        private static IQuery<ModelPublicationInfo3> GetModelPublications3(IParam<string> modelCode, IParam<string> modelSequence)
        {
            return new Q(@"SELECT
    ModelPublication.PublicationId,
    ModelPublication.ModelCode,
    ModelPublication.ModelSequence
FROM
    ModelPublication
WHERE
    ModelPublication.ModelCode = ")._(modelCode)._(@"
    AND ModelPublication.ModelSequence = ")._(modelSequence).Query<ModelPublicationInfo3>();
        }
    }

    public interface IModelPublicationInfo1
    {
        Guid PublicationId { get; }
        NVarChar<L4000> ModelCode { get; }
        NVarChar<L4000> ModelSequence { get; }
    }

    public class ModelPublicationInfo3
    {
        private readonly Guid publicationId;
        private readonly NVarChar<L4000> modelCode;
        private readonly NVarChar<L4000> modelSequence;

        public ModelPublicationInfo3(Guid publicationId, NVarChar<L4000> modelCode, NVarChar<L4000> modelSequence)
        {
            this.publicationId = publicationId;
            this.modelCode = modelCode;
            this.modelSequence = modelSequence;
        }

        public Guid PublicationId
        {
            get { return publicationId; }
        }

        public NVarChar<L4000> ModelCode
        {
            get { return modelCode; }
        }

        public NVarChar<L4000> ModelSequence
        {
            get { return modelSequence; }
        }
    }
}